﻿using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Queue;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web.Http;
using System.Web.Helpers;
using System.Web.Mvc;
using Webservice.Entities;
using Webservice.Models;
using Newtonsoft.Json;
using System.Configuration;

namespace Webservice.Controllers
{
    public class ReportController : ApiController
    {
        private CloudTable rawdataTable;
        private CloudQueue reportQueue;
        private CloudBlobContainer reportContainer;

#error STORAGE_CONNECTION_STRING must be defined in app.config
        static private string STORAGE_CONNECTION_STRING = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

        public ReportController()
        {
            var storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(STORAGE_CONNECTION_STRING);
            var blobClient = storageAccount.CreateCloudBlobClient();
            var tableClient = storageAccount.CreateCloudTableClient();
            var queueClient = storageAccount.CreateCloudQueueClient();

            rawdataTable = tableClient.GetTableReference("moments");
            rawdataTable.CreateIfNotExists();

            reportQueue = queueClient.GetQueueReference("vehiclereportqueue");
            reportQueue.CreateIfNotExists();

            reportContainer = blobClient.GetContainerReference("reports");
            reportContainer.CreateIfNotExists();
        }

        int row = 0;
        private void StoreData(string contents)
        {
            ReportRequestEntity newReport = new ReportRequestEntity()
            {
                ReportGUID = Guid.NewGuid().ToString("N"),
                RowKey = DateTime.Now.ToString()
            };

            List<MomentModel> models = JsonConvert.DeserializeObject<List<MomentModel>>(contents);

            TableBatchOperation batchOperation = new TableBatchOperation();
            foreach (MomentModel model in models)
            {
                MomentEntity moment = new MomentEntity(newReport.ReportGUID, row++, model);

                if (newReport.VIN == null && moment.VIN.Length == 17)
                    newReport.VIN = moment.VIN;

                batchOperation.Insert(moment);
                if (batchOperation.Count == 50)
                {
                    rawdataTable.ExecuteBatch(batchOperation);
                    batchOperation.Clear();
                }
            }

            rawdataTable.ExecuteBatch(batchOperation);
            reportQueue.AddMessage(new CloudQueueMessage(newReport.ReportGUID + "," + newReport.VIN));
        }

        /*
        private bool StoreData(string csvstring)
        {
            ReportRequestEntity newReport = new ReportRequestEntity()
            {
                ReportGUID = Guid.NewGuid().ToString("N"),
                RowKey = DateTime.Now.ToString()
            };
            
            TableBatchOperation batchOperation = new TableBatchOperation();

            ICsvParser csvParser = new CsvParser(new StringReader(csvstring)); /// Opens previously uploaded file and parses 
            CsvReader csvReader = new CsvReader(csvParser); // Creates reader to read parsed CSV file

            string[] headers = { }; // We will hold our CSV headers here

            int row = 0;
            while (csvReader.Read()) // Begin reading line by line
            {
                MomentEntity moment = new Entities.MomentEntity()
                {
                    Entry = row++,
                    PartitionKey = newReport.ReportGUID
                };

                headers = csvReader.FieldHeaders; // If this a header line, grab the headers

                try
                {
                    this.ValidateFormat(headers);
                }
                catch (System.ArgumentException e)
                {
                    Debug.Print(e.Message);
                    return false;
                }

                for (int j = 0; j < headers.Count(); j++) // Loop through each field and save property value to snapshot
                {
                    string propertyName = headers[j]; // Property name of the snapshot property, must be the same as the header field
                    PropertyInfo propertyInfo = moment.GetType().GetProperty(propertyName);
                    if (propertyInfo != null)
                    {
                        object value = csvReader.GetField(j); // Gets the value of the current field

                        #region Identify and set properties

                        switch (propertyName)
                        {
                            case "VIN":
                                {
                                    Regex alphanumeric = new Regex("[^A-Z0-9]");
                                    Regex vinformat = new Regex("[IOQ]");

                                    value = alphanumeric.Replace((string)value, "");
                                    value = vinformat.Replace((string)value, "");

                                    break;
                                }
                            case "XAxis":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (System.Exception)
                                    {
                                        Debug.Print("Could not parse X Acceleration (" + value + ")");
                                    }

                                    break;
                                }
                            case "YAxis":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (System.Exception)
                                    {
                                        Debug.Print("Could not parse Y Acceleration (" + value + ")");
                                    }

                                    break;
                                }
                            case "ZAxis":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (System.Exception)
                                    {
                                        Debug.Print("Could not parse Z Acceleration (" + value + ")");
                                    }

                                    break;
                                }
                            case "Speed":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (SystemException)
                                    {
                                        Debug.Print("Could not parse Speed (" + value + ")");
                                    }
                                    break;
                                }
                            case "Heading":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (SystemException)
                                    {
                                        Debug.Print("Could not parse Heading (" + value + ")");
                                    }
                                    break;
                                }
                            case "Latitude":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (SystemException)
                                    {
                                        Debug.Print("Could not parse Latitude (" + value + ")");
                                    }

                                    break;
                                }
                            case "Longitude":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (SystemException)
                                    {
                                        Debug.Print("Could not parse Longitude (" + value + ")");
                                    }

                                    break;
                                }
                            case "Fuel":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (SystemException)
                                    {
                                        Debug.Print("Could not parse Fuel (" + value + ")");
                                    }

                                    break;
                                }
                            case "Throttle":
                                {
                                    try
                                    {
                                        value = double.Parse((string)value);
                                    }
                                    catch (SystemException)
                                    {
                                        Debug.Print("Could not parse Throttle (" + value + ")");
                                    }

                                    break;
                                }
                        }
                        propertyInfo.SetValue(moment, value, null);

                        #endregion
                    }
                }
                
                if (newReport.VIN == null && moment.VIN.Length == 17)
                    newReport.VIN = moment.VIN;

                batchOperation.Insert(moment);
                if (batchOperation.Count == 50)
                {
                    rawdataTable.ExecuteBatch(batchOperation);
                    batchOperation.Clear();
                }
            }
            
            rawdataTable.ExecuteBatch(batchOperation);
            reportQueue.AddMessage(new CloudQueueMessage(newReport.ReportGUID + "," + newReport.VIN));

            return true;
        }
        */

        // GET api/api
        public List<Contracts.Report> Get()
        {
            StorageService storageClient = new StorageService();
            List<Contracts.Report> reports = storageClient.GetReports();

            return reports;
        }
        
        // GET api/api/5
        public string Get(string id)
        {
            StorageService storageClient = new StorageService();

            try
            {
                return storageClient.GetReport(id);
            }
            catch(System.IO.FileNotFoundException)
            {
                var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
                {
                    Content = new StringContent(string.Format("No report with id {0} exists", id)),
                    ReasonPhrase = "Report ID Not Found"
                };

                throw new HttpResponseException(resp);
            }   
        }
        
        // POST api/api
        public string Post([FromBody]string value)
        {
            if (value.Length == 0)
                return "failed";
            
            try
            {
                return "success";
            }
            catch(SystemException)
            {
                return "failed";
            }
        }

        // PUT api/api/5
        public string Put(string identifier, [FromBody]string value)
        {
            if (value.Length == 0)
                return "failed";

            try
            {
                return "success";
            }
            catch (SystemException)
            {
                return "failed";
            }
        }

        // DELETE api/api/5
        public void Delete(int id)
        {
        }
    }
}
